#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
IR 异常处理语句节点定义
"""

import ast
from dataclasses import dataclass, field
from typing import Optional, Iterator, List
from .base import IRStmt, IRStmtBlock
from ..base import IRNode
from ..expressions import build_expr_from_ast
from mcpy.symbol_meta import Symbol, SymbolKind


@dataclass
class IRRaise(IRStmt):
    """raise 语句"""

    exc: Optional[IRNode] = field(default=None)  # 异常对象或异常类型
    cause: Optional[IRNode] = field(default=None)  # from 子句（异常链，Python 3.3+）
    node_type: str = "raise"

    def get_child_nodes(self) -> Iterator[IRNode]:
        """获取所有子节点"""
        if self.exc is not None:
            yield self.exc
        if self.cause is not None:
            yield self.cause
        yield from super().get_child_nodes()

    def build_from_ast(self, node: ast.Raise) -> None:
        """从 AST raise 节点构建 IR raise 节点内容

        Args:
            node: AST raise 节点
        """
        super().build_from_ast(node)

        if node.exc:
            self.exc = build_expr_from_ast(node.exc, self)

        if node.cause:
            self.cause = build_expr_from_ast(node.cause, self)


@dataclass
class IRExceptionHandler(IRNode):
    """异常处理器（except 子句）

    注意：IRExceptionHandler 创建作用域以隔离异常变量（as name）
    异常变量（as name）定义在此节点中
    """

    type: Optional[IRNode] = field(default=None)  # 捕获的异常类型
    exception_name: Optional[str] = field(default=None)  # 异常变量名（as name）
    body: Optional[IRStmtBlock] = field(default=None)  # 处理代码块
    node_type: str = "exception_handler"

    def creates_scope(self) -> bool:
        """异常处理器创建作用域以隔离异常变量"""
        return True

    def __post_init__(self):
        """初始化后处理"""
        if self.body is None:
            self.body = IRStmtBlock()

    def get_child_nodes(self) -> Iterator[IRNode]:
        """获取所有子节点"""
        if self.type is not None:
            yield self.type
        if self.body:
            yield self.body
        yield from super().get_child_nodes()

    def get_local_symbols(self) -> Iterator["Symbol"]:
        """获取 except 块中定义的符号

        包括：
        1. 异常变量（as name）
        2. except 块内部定义的其他符号

        Returns:
            本地符号的迭代器
        """
        # 异常变量符号
        if self.exception_name:
            yield Symbol(
                name=self.exception_name,
                kind=SymbolKind.VARIABLE,
                ir_node=self,
            )

        if self.body:
            yield from self.body.get_local_symbols()


@dataclass
class IRTryExcept(IRStmt):
    """try/except/finally 语句"""

    body: Optional[IRStmtBlock] = field(default=None)  # try 块
    handlers: List[IRExceptionHandler] = field(default_factory=list)  # except 子句列表
    orelse: Optional[IRStmtBlock] = field(default=None)  # else 子句
    finalbody: Optional[IRStmtBlock] = field(default=None)  # finally 子句
    node_type: str = "try_except"

    def __post_init__(self):
        """初始化后处理"""
        if self.body is None:
            self.body = IRStmtBlock()

    def get_child_nodes(self) -> Iterator[IRNode]:
        """获取所有子节点"""
        if self.body:
            yield self.body
        for handler in self.handlers:
            yield handler
        if self.orelse:
            yield self.orelse
        if self.finalbody:
            yield self.finalbody
        yield from super().get_child_nodes()

    def get_local_symbols(self):
        """获取try/except语句中定义的所有本地符号

        Returns:
            本地符号的迭代器
        """
        # try 块中的符号
        if self.body:
            yield from self.body.get_local_symbols()

        # except 子句中的符号（包括异常变量和块内符号）
        for handler in self.handlers:
            yield from handler.get_local_symbols()

        # else 块中的符号
        if self.orelse:
            yield from self.orelse.get_local_symbols()

        # finally 块中的符号
        if self.finalbody:
            yield from self.finalbody.get_local_symbols()

    def build_from_ast(self, node: ast.Try) -> None:
        """从 AST try 节点构建 IR try/except 节点内容

        Args:
            node: AST try 节点
        """
        super().build_from_ast(node)

        # 构建 try 块
        self.body = IRStmtBlock()
        self.body.set_parent(self)
        self.body.build_from_ast(node.body)

        # 构建 except 子句
        for handler_node in node.handlers:
            handler = IRExceptionHandler(parent=self)
            if handler_node.type:
                handler.type = build_expr_from_ast(handler_node.type, handler)
            if handler_node.name:
                handler.exception_name = handler_node.name
            handler.body = IRStmtBlock()
            handler.body.set_parent(handler)  # body 的 parent 是 handler
            handler.body.build_from_ast(handler_node.body)
            self.handlers.append(handler)

        # 构建 else 子句
        if node.orelse:
            self.orelse = IRStmtBlock()
            self.orelse.set_parent(self)
            self.orelse.build_from_ast(node.orelse)

        # 构建 finally 子句
        if node.finalbody:
            self.finalbody = IRStmtBlock()
            self.finalbody.set_parent(self)
            self.finalbody.build_from_ast(node.finalbody)
